#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <errno.h>
#include "utest.h"

typedef struct {
    int id;
    char *desc;
    void (*fp)();
    int ok;
} utest_t;

static int utest_capacity;
static utest_t *utest_array;
static int utest_count;
static int utest_log;

void utest_add(char *desc, void (*fp)())
{
    assert(utest_count <= utest_capacity);

    if (utest_capacity == 0) {
        utest_capacity = 2;
        utest_array = malloc(utest_capacity * sizeof(utest_t));
    }

    if (utest_count == utest_capacity) {
        utest_capacity *= 2;
        utest_array = realloc(utest_array, utest_capacity * sizeof(utest_t));
    }

    utest_t *utest = utest_array + utest_count;
    utest->id = utest_count;
    utest->desc = strdup(desc);
    utest->fp = fp;
    utest_count++;
}

void utest_parse_args(int argc, char *argv[], char *target_arg, void (*fp)())
{
    for (int i = 0; i < argc; i++) {
        char *arg = argv[i];
        if (strcmp(arg, target_arg) == 0) {
            fp();
            exit(EXIT_SUCCESS);
        }
    }
}

void utest_exec(utest_t *utest)
{
	int fd = open("utest.log", O_WRONLY | O_APPEND | O_CREAT, 0666);
	if(fd < 0)
		printf("open error\n");
	dup2(fd, 2);
	close(fd);
	utest->fp();
}

void utest_run(void)
{
    int i, flag = 0;
    unlink("utest.log");
    for (i = 0; i < utest_count; i++) {
        pid_t pid = fork();
        if (pid == 0) {
            alarm(3);
            utest_exec(utest_array + i);
            exit(0);
        }
	int status;
	int error = waitpid(pid, &status, 0);
	if ((error > 0) && WIFEXITED(status) && (WEXITSTATUS(status) == 0)) {
		(utest_array + i)->ok = 0;
		printf("%03d: %s	OK\n", (utest_array + i)->id, (utest_array + i)->desc);
	} else {
		flag = 1;
		(utest_array + i)->ok = 1;
		printf("%03d: %s	Failed\n", (utest_array + i)->id, (utest_array + i)->desc);
	}
    }
    if (flag == 1) {
	    printf("The following test failed:\n");
	    for (i = 0; i < utest_count; ++i) {
		    if((utest_array + i)->ok == 1) 
			    printf("%03d: %s\n", (utest_array + i)->id, (utest_array + i)->desc);
	    }
	    printf("See utest.log for details.\n");
    }
}
